﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SLPropertyGrid
{
    public class PropertyGrid : Control
    {
        public static readonly DependencyProperty InstanceProperty
            = DependencyProperty.Register("Instance", typeof(object), typeof(PropertyGrid),
                                          new PropertyMetadata(null, OnInstanceChanged)
                );
        public static readonly DependencyProperty PropertiesProperty
            = DependencyProperty.Register("Properties", typeof(IList<PropertyCategory>), typeof(PropertyGrid),
                                          new PropertyMetadata(null)
                );

        public static readonly DependencyProperty LabelWidthProperty
    = DependencyProperty.Register("LabelWidth", typeof(GridLength), typeof(PropertyGrid),
                                  new PropertyMetadata(new GridLength(1.0), LabelWidthChanged)
        );

        private static void LabelWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {


        }

        public PropertyGrid()
        {
            DefaultStyleKey = typeof(PropertyGrid);

            this.BindingValidationError += Root_BindingValidationError;
        }

        public object Instance
        {
            get
            {
                return base.GetValue(InstanceProperty);
            }
            set
            {
                base.SetValue(InstanceProperty, value);
            }
        }

        public IList<PropertyCategory> Properties
        {
            get
            {
                return (IList<PropertyCategory>)base.GetValue(PropertiesProperty);
            }
            set
            {
                base.SetValue(PropertiesProperty, value);
            }
        }

        public GridLength LabelWidth
        {
            get
            {
                return (GridLength)base.GetValue(LabelWidthProperty);
            }
            set
            {
                base.SetValue(LabelWidthProperty, value);
            }
        }


        private static void OnInstanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PropertyGrid propertyGrid = d as PropertyGrid;
            if (propertyGrid != null)
            {
                IList<PropertyCategory> properties = ExtractPropertiesWithCategory(e.NewValue);
                propertyGrid.Properties = properties;
            }
        }

        private static PropertyCollection ExtractProperties(object ob)
        {
            PropertyCollection pc = new PropertyCollection();
            Type t = ob.GetType();
            var props = t.GetProperties();

            foreach (PropertyInfo pinfo in props)
            {
                var v = pinfo.GetIndexParameters();
                
                if (v != null && v.Length > 0)
                    continue;

                Property prop = new Property(ob, pinfo);                
                pc.Add(prop);
                if (prop.Category != null)
                    Debug.WriteLine("Property {0} has cat {1}", prop.Name, prop.Category);
            }

            return pc;
        }

        private static IList<PropertyCategory> ExtractPropertiesWithCategory(object ob)
        {
            Dictionary<string, PropertyCategory> _dict = new Dictionary<string, PropertyCategory>();
            //PropertyCategory pc = new PropertyCollection();
            Type t = ob.GetType();
            var props = t.GetProperties();

            foreach (PropertyInfo pinfo in props)
            {
                ParameterInfo[] parameters = pinfo.GetIndexParameters();
                //we don't support indexed properties at the moment
                if (parameters.Length == 0)
                {
                    Property prop = new Property(ob, pinfo);
                    string cat = prop.Category ?? "Misc";
                    if (!_dict.ContainsKey(cat))
                        _dict.Add(cat, new PropertyCategory() { Name = cat });
                    _dict[cat].Properties.Add(prop);
                }

            }

            return _dict.Values.ToList();
        }

        private void Root_BindingValidationError(object sender, ValidationErrorEventArgs e)
        {



        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            /*
                        ColumnDefinition def = GetTemplateChild("def") as ColumnDefinition;
                        IntBindingSynch bs = (IntBindingSynch) FindName("bindingSynch") ;
                        def.Width = new GridLength(20.0);
                        Binding binding = new Binding(); 
                        binding.Source = def;
                        binding.Path =new PropertyPath("Width");
                        binding.Mode = BindingMode.TwoWay;

                        SetBinding(PropertyGrid.LabelWidthProperty, binding); 
            */
        }

        public void ExploreVisualTree()
        {
            IList<DependencyObject> descendants = Helper.ExploreVisualTree(this, o => true);

        }
    }
}
